package com.yxc.validationdemo.handler;

import com.alibaba.fastjson.JSONException;
import com.yxc.validationdemo.entity.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.time.format.DateTimeParseException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理
 *
 * @author 杨旭晨
 * @copyright (C), 2019-2021, 河北地质大学
 * @filename GlobalExceptionHandler
 * @date 2021/5/3 11:05
 * @history <author>     <time>      <version>       <desc>
 * 作者名       修改时间       版本号           描述
 **/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 方法不支持异常处理
     *
     * @param e:
     * @return com.xgkx.procurement.common.entity.R
     * @author 杨旭晨
     * @date 11:10 2021/5/3
     **/
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public String HttpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        e.printStackTrace();
        return R.error("方法不支持").toJSONString();
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public String httpMessageNotReadableExceptionMethod(HttpMessageNotReadableException e) {
        StringBuilder sb = new StringBuilder();
        sb.append("参数异常；");
        if (e.getCause() != null && e.getCause() instanceof JSONException) {
            sb.append("json格式化失败；");
            if (e.getCause() != null && e.getCause().getCause() != null && e.getCause().getCause() instanceof DateTimeParseException) {
                sb.append("时间格式化失败：" + ((DateTimeParseException) e.getCause().getCause()).getParsedString());
            }
        }
        log.error(sb.toString());
        e.printStackTrace();
        return R.error(sb.toString()).toJSONString();
    }

    /**
     * 参数校验失败异常捕获
     *
     * @author YXC
     * @date 2022/10/17 17:28
     * @param request:
     * @param response:
     * @param e:
     * @return void
    **/
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public String methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        Iterator<ObjectError> iterator = allErrors.iterator();
        StringBuilder builder = new StringBuilder();
        while (iterator.hasNext()) {
            FieldError error = (FieldError) iterator.next();

            String message = error.getField() + ":" + error.getDefaultMessage() + "(" + error.getRejectedValue() + ")";
            builder.append(message);
        }
        return R.error(builder.toString()).toJSONString();
    }

    /**
     * 捕获参数校验失败异常
     *
     * @author YXC
     * @date 2022/11/9 15:18
     * @param request:
     * @param response:
     * @param e:
     * @return void
    **/
   @ExceptionHandler(ConstraintViolationException.class)
   public String constraintViolationExceptionHandler(ConstraintViolationException e) {
       StringBuilder sb = new StringBuilder();
       Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
       for (ConstraintViolation<?> constraintViolation : constraintViolations) {
           String message = constraintViolation.getMessageTemplate();
           sb.append(message)
                   .append(": ")
                   .append(constraintViolation.getInvalidValue())
                   .append(";\n");
       }
       sb.delete(sb.lastIndexOf("\n"), sb.length());
       return R.error(sb.toString()).toJSONString();
   }

    /**
     * 处理时间格式错误异常
     *
     * @author YXC
     * @date 2022/10/18 10:17
     * @param request:
     * @param response:
     * @param e:
     * @return void
    **/
    @ExceptionHandler(value = DateTimeParseException.class)
    public String dateTimeParseExceptionHandler(DateTimeParseException e) {
        log.error("时间格式异常: {}", e.getParsedString());
        return R.error("时间格式异常: " + e.getParsedString()).toJSONString();
    }

    /**
     * 捕获缺少参数的错误
     *
     * @author YXC
     * @date 2022/11/9 15:50
     * @param request:
     * @param response:
     * @param e:
     * @return void
    **/
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public String missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        StringBuilder sb = new StringBuilder();
        sb.append("缺少参数：")
                .append(e.getParameterName())
                .append("(").append(e.getParameterType()).append(")");
        return R.error(sb.toString()).toJSONString();
    }

    /**
     * 处理其他异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public String exceptionHandler(Exception e) {
        log.error("错误{}", e.getMessage());
        e.printStackTrace();
        return R.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "未知错误：" + e.getMessage()).toJSONString();
    }

}
